﻿using System;
using System.Runtime.InteropServices;
using UnityEngine;

[AddComponentMenu("FingerGestures/Toolbox/Input Manager")]
public class TBInputManager : MonoBehaviour
{
    public Collider dragPlaneCollider;
    public float dragPlaneOffset;
    public DragPlaneType dragPlaneType = DragPlaneType.Camera;
    public LayerMask ignoreLayers = 0;
    public Camera raycastCamera;
    public bool trackDrag = true;
    public bool trackFingerDown = true;
    public bool trackFingerUp = true;
    public bool trackLongPress = true;
    public bool trackSwipe = true;
    public bool trackTap = true;

    private void draggable_OnDragEnd(TBDrag source)
    {
        source.OnDragMove -= new TBComponent.EventHandler<TBDrag>(this.draggable_OnDragMove);
        source.OnDragEnd -= new TBComponent.EventHandler<TBDrag>(this.draggable_OnDragEnd);
    }

    private void draggable_OnDragMove(TBDrag sender)
    {
        Vector3 vector2;
        Vector3 vector3;
        Vector2 screenPos = sender.FingerPos - sender.MoveDelta;
        if (this.ProjectScreenPointOnDragPlane(sender.transform.position, screenPos, out vector3) && this.ProjectScreenPointOnDragPlane(sender.transform.position, sender.FingerPos, out vector2))
        {
            Vector3 vector4 = vector2 - vector3;
            Transform transform = sender.transform;
            transform.position += vector4;
        }
    }

    private void FingerGestures_OnFingerDown(int fingerIndex, Vector2 fingerPos)
    {
        TBFingerDown down = this.PickComponent<TBFingerDown>(fingerPos);
        if (down != null)
        {
            down.RaiseFingerDown(fingerIndex, fingerPos);
        }
    }

    private void FingerGestures_OnFingerDragBegin(int fingerIndex, Vector2 fingerPos, Vector2 startPos)
    {
        TBDrag drag = this.PickComponent<TBDrag>(startPos);
        if ((drag != null) && !drag.Dragging)
        {
            drag.BeginDrag(fingerIndex, fingerPos);
            drag.OnDragMove += new TBComponent.EventHandler<TBDrag>(this.draggable_OnDragMove);
            drag.OnDragEnd += new TBComponent.EventHandler<TBDrag>(this.draggable_OnDragEnd);
        }
    }

    private void FingerGestures_OnFingerLongPress(int fingerIndex, Vector2 fingerPos)
    {
        TBLongPress press = this.PickComponent<TBLongPress>(fingerPos);
        if (press != null)
        {
            press.RaiseLongPress(fingerIndex, fingerPos);
        }
    }

    private void FingerGestures_OnFingerSwipe(int fingerIndex, Vector2 startPos, FingerGestures.SwipeDirection direction, float velocity)
    {
        TBSwipe swipe = this.PickComponent<TBSwipe>(startPos);
        if (swipe != null)
        {
            swipe.RaiseSwipe(fingerIndex, startPos, direction, velocity);
        }
    }

    private void FingerGestures_OnFingerTap(int fingerIndex, Vector2 fingerPos, int tapCount)
    {
        TBTap tap = this.PickComponent<TBTap>(fingerPos);
        if (tap != null)
        {
            tap.RaiseTap(fingerIndex, fingerPos, tapCount);
        }
    }

    private void FingerGestures_OnFingerUp(int fingerIndex, Vector2 fingerPos, float timeHeldDown)
    {
        TBFingerUp up = this.PickComponent<TBFingerUp>(fingerPos);
        if (up != null)
        {
            up.RaiseFingerUp(fingerIndex, fingerPos, timeHeldDown);
        }
    }

    private void OnDisable()
    {
        FingerGestures.OnFingerDown -= new FingerGestures.FingerDownEventHandler(this.FingerGestures_OnFingerDown);
        FingerGestures.OnFingerUp -= new FingerGestures.FingerUpEventHandler(this.FingerGestures_OnFingerUp);
        FingerGestures.OnFingerDragBegin -= new FingerGestures.FingerDragBeginEventHandler(this.FingerGestures_OnFingerDragBegin);
        FingerGestures.OnFingerTap -= new FingerGestures.FingerTapEventHandler(this.FingerGestures_OnFingerTap);
        FingerGestures.OnFingerLongPress -= new FingerGestures.FingerLongPressEventHandler(this.FingerGestures_OnFingerLongPress);
        FingerGestures.OnFingerSwipe -= new FingerGestures.FingerSwipeEventHandler(this.FingerGestures_OnFingerSwipe);
    }

    private void OnEnable()
    {
        if (this.trackFingerDown)
        {
            FingerGestures.OnFingerDown += new FingerGestures.FingerDownEventHandler(this.FingerGestures_OnFingerDown);
        }
        if (this.trackFingerUp)
        {
            FingerGestures.OnFingerUp += new FingerGestures.FingerUpEventHandler(this.FingerGestures_OnFingerUp);
        }
        if (this.trackDrag)
        {
            FingerGestures.OnFingerDragBegin += new FingerGestures.FingerDragBeginEventHandler(this.FingerGestures_OnFingerDragBegin);
        }
        if (this.trackTap)
        {
            FingerGestures.OnFingerTap += new FingerGestures.FingerTapEventHandler(this.FingerGestures_OnFingerTap);
        }
        if (this.trackLongPress)
        {
            FingerGestures.OnFingerLongPress += new FingerGestures.FingerLongPressEventHandler(this.FingerGestures_OnFingerLongPress);
        }
        if (this.trackSwipe)
        {
            FingerGestures.OnFingerSwipe += new FingerGestures.FingerSwipeEventHandler(this.FingerGestures_OnFingerSwipe);
        }
    }

    private T PickComponent<T>(Vector2 screenPos) where T: TBComponent
    {
        GameObject obj2 = this.PickObject(screenPos);
        if (obj2 == null)
        {
            return null;
        }
        return obj2.GetComponent<T>();
    }

    private GameObject PickObject(Vector2 screenPos)
    {
        RaycastHit hit;
        if (Physics.Raycast(Camera.main.ScreenPointToRay((Vector3) screenPos), out hit, float.MaxValue, (int) ~this.ignoreLayers))
        {
            return hit.collider.gameObject;
        }
        return null;
    }

    private bool ProjectScreenPointOnDragPlane(Vector3 refPos, Vector2 screenPos, out Vector3 worldPos)
    {
        worldPos = refPos;
        switch (this.dragPlaneType)
        {
            case DragPlaneType.XY:
                worldPos = this.raycastCamera.ScreenToWorldPoint(new Vector3(screenPos.x, screenPos.y, Mathf.Abs((float) (refPos.z - this.raycastCamera.transform.position.z))));
                return true;

            case DragPlaneType.XZ:
                worldPos = this.raycastCamera.ScreenToWorldPoint(new Vector3(screenPos.x, screenPos.y, Mathf.Abs((float) (refPos.y - this.raycastCamera.transform.position.y))));
                return true;

            case DragPlaneType.ZY:
                worldPos = this.raycastCamera.ScreenToWorldPoint(new Vector3(screenPos.x, screenPos.y, Mathf.Abs((float) (refPos.x - this.raycastCamera.transform.position.x))));
                return true;

            case DragPlaneType.UseCollider:
            {
                RaycastHit hit;
                Ray ray = this.raycastCamera.ScreenPointToRay((Vector3) screenPos);
                if (this.dragPlaneCollider.Raycast(ray, out hit, float.MaxValue))
                {
                    worldPos = hit.point + ((Vector3) (this.dragPlaneOffset * hit.normal));
                    return true;
                }
                return false;
            }
            case DragPlaneType.Camera:
            {
                Transform transform = this.raycastCamera.transform;
                Plane plane = new Plane(-transform.forward, refPos);
                Ray ray2 = this.raycastCamera.ScreenPointToRay((Vector3) screenPos);
                float enter = 0f;
                if (plane.Raycast(ray2, out enter))
                {
                    worldPos = ray2.GetPoint(enter);
                    return true;
                }
                return false;
            }
        }
        return false;
    }

    private void Start()
    {
        if (this.raycastCamera == null)
        {
            this.raycastCamera = Camera.main;
        }
    }

    public enum DragPlaneType
    {
        XY,
        XZ,
        ZY,
        UseCollider,
        Camera
    }
}

